﻿using System;
using System.Data;
using NUnit.Framework;


namespace Microsoft.Practices.Repository.Tests
{
    /// <summary>
    /// Tests for the <see cref="CastDBValue"/> class.
    /// </summary>
    [TestFixture]
    public class CastDBValueTest
    {
        [Test()]
        public void CheckStringAsNull()
        {
            string result = CastDBValue.ToOptional<string>(DBNull.Value, null);
            Assert.IsNull(result);
        }

        [Test()]
        public void CheckStringAsEmpty()
        {
            string result = CastDBValue.ToOptional<string>(DBNull.Value, string.Empty);
            Assert.AreEqual(string.Empty, result);
        }

        [Test()]
        public void CheckStringAsLiteral()
        {
            string defaultLiteral = "whatever";
            string result = CastDBValue.ToOptional<string>(DBNull.Value, defaultLiteral);
            Assert.AreEqual(defaultLiteral, result);
        }

        [Test()]
        public void CheckNullableIntegerAsNull()
        {
            int? result = CastDBValue.ToOptional<int?>(DBNull.Value, null);
            Assert.IsNull(result);
        }

        [Test()]
        public void CheckReaderOptionalValue()
        {
            string result = CastDBValue.ToOptional<string>(GetReader<string>("value1"), "col1", "default");
            Assert.AreEqual("value1", result);
        }

        [Test()]
        public void CheckReaderOptionalNull()
        {
            string result = CastDBValue.ToOptional<string>(GetReader<string>(null), "col1", "default");
            Assert.AreEqual("default", result);
        }

        [Test()]
        public void CheckReaderOptionalDBNull()
        {
            string result = CastDBValue.ToOptional<string>(GetReader<object>(DBNull.Value), "col1", "default");
            Assert.AreEqual("default", result);

        }

        [Test()]
        public void CheckReaderRequiredValue()
        {
            string result = CastDBValue.ToRequired<string>(GetReader<string>("value1"), "col1");
            Assert.AreEqual("value1", result);
        }
        
        [Test()]
        [ExpectedException(typeof(DBValueNullException))]
        public void CheckReaderRequiredNull()
        {
            string result = CastDBValue.ToRequired<string>(GetReader<string>(null), "col1");
            Assert.AreEqual("default", result);
        }
        
        [Test()]
        [ExpectedException(typeof(DBValueNullException))]
        public void CheckReaderRequiredDBNull()
        {
            string result = CastDBValue.ToRequired<string>(GetReader<object>(DBNull.Value), "col1");
            Assert.AreEqual("default", result);
        }
        
        [Test()]
        [ExpectedException(typeof(DBValueNullException))]
        public void CheckReaderRequiredDBNullWithExtraMessage()
        {
            string result = CastDBValue.ToRequired<string>(GetReader<object>(DBNull.Value), "col1", "Key for this row is 1");
            Assert.AreEqual("default", result);
        }

        [Test()]
        public void CheckReaderRequiredIntegerDbTypeDecimalTargetType()
        {
            int targetValue = int.MinValue;
            decimal result = CastDBValue.ToRequired<decimal>(GetReader<int>(targetValue), "col1");
            Assert.AreEqual(targetValue.ToString(), result.ToString());
        }

        [Test()]
        [ExpectedException(ExceptionType=typeof(OverflowException))]
        public void CheckReaderRequiredDecimalDbTypeIntegerTargetType()
        {
            decimal targetValue = decimal.MaxValue;
            int result = CastDBValue.ToRequired<int>(GetReader<decimal>(targetValue), "col1");
            Assert.AreEqual(targetValue.ToString(), result.ToString());
        }

        [Test()]
        public void CheckReaderOptionalIntegerDbTypeDecimalTargetType()
        {
            int? targetValue = null;
            decimal? result = CastDBValue.ToOptional<decimal?>(GetReader<object>(targetValue), "col1", null);
            Assert.IsFalse(result.HasValue);
        }

        [Test()]
        public void CheckReaderOptionalIntegerDbTypeNullableDecimalTargetType()
        {
            int targetValue = int.MinValue;
            decimal? result = CastDBValue.ToOptional<decimal?>(GetReader<int>(targetValue), "col1", int.MinValue);
            Assert.IsTrue(result.HasValue);
            Assert.IsTrue(result.Value == (decimal)targetValue);
        }

        private IDataReader GetReader<T>(T value)
        {
            DataTable data = new DataTable();
            data.Columns.Add("col1");
            data.Columns[0].DataType = typeof(T);
            data.Rows.Add(data.NewRow());
            data.Rows[0]["col1"] = value;
            IDataReader reader = new DataTableReader(data);
            reader.Read();
            return reader;
        }
    }
}

